#include <QGuiApplication>
#include <QVariant>
#include <QTextStream>
#include <QDebug>

#include <wayland-client-protocol.h>
#include <wayland-client.h>
#include <Registry.hpp>
#include <WayQtUtils.hpp>
#include <Output.hpp>
#include <OutputManager.hpp>
#include <GammaControl.hpp>
#include <TreeLandOutputManager.hpp>

#include <DFGammaEffects.hpp>

using namespace DFL;
using namespace WQt;

constexpr auto wlTransformEnumToName(wl_output_transform transform)
{
    switch (transform) {
    case WL_OUTPUT_TRANSFORM_NORMAL:
        return "normal";
    case WL_OUTPUT_TRANSFORM_90:
        return "90";
    case WL_OUTPUT_TRANSFORM_180:
        return "180";
    case WL_OUTPUT_TRANSFORM_270:
        return "270";
    case WL_OUTPUT_TRANSFORM_FLIPPED:
        return "flipped";
    case WL_OUTPUT_TRANSFORM_FLIPPED_90:
        return "flipped-90";
    case WL_OUTPUT_TRANSFORM_FLIPPED_180:
        return "flipped-180";
    case WL_OUTPUT_TRANSFORM_FLIPPED_270:
        return "flipped-270";
    }
    Q_UNREACHABLE();
}

int main(int argc, char *argv[])
{
    qputenv("QT_QPA_PLATFORM", "wayland");

    QGuiApplication a(argc, argv);
    QTextStream qout(stdout);

    struct wl_display *display = wl_display_connect(NULL);
    if (display == NULL) {
        qFatal("failed to connect to display\n");
        exit(EXIT_FAILURE);
    }

    auto *reg = new WQt::Registry(WQt::Wayland::display());

    reg->setup();

    auto *opMgr = reg->outputManager();

    if (!opMgr) {
        qFatal("Unable to start the output manager");
    }

    opMgr->waitForDone();

    for (auto *head : opMgr->heads()) {
        // Name
        qout << head->property(WQt::OutputHead::Name).toString() << " ";
        // Description
        qout << '"' << head->property(WQt::OutputHead::Description).toString() << '"' << Qt::endl;
        // Enabled
        qout << QString(" Enabled: %1").arg(head->property(WQt::OutputHead::Enabled).toBool() ? "yes" : "no") << Qt::endl;

        // Modes
        qout << "Modes:" << Qt::endl;
        for (auto *mode: head->property(WQt::OutputHead::Modes).value<QList<WQt::OutputMode *>>()) {
            QString modeStr = QString("%1 x %2 @ %3 Hz").arg(mode->size().width()).arg(mode->size().height());
            modeStr         = modeStr.arg(mode->refreshRate() / 1000.0, 0, 'g', 3);
            modeStr        += (mode->isPreferred() ? " *" : "");
            qout << "  " << modeStr << Qt::endl;
        }
        // Position
        auto pos = head->property(WQt::OutputHead::Position).toPoint();
        qout << QString(" Position: %1 %2").arg(pos.x()).arg(pos.y()) << Qt::endl;

        // Transform
        QString transform = wlTransformEnumToName(static_cast<wl_output_transform>(
                                                      head->property(WQt::OutputHead::Transform).toInt()
                                                      ));
        qout << QString(" Transform: %1").arg(transform) << Qt::endl;

        // Scale
        qout << QString(" Scale: %1").arg(head->property(WQt::OutputHead::Scale).toFloat()) << Qt::endl;
    }


    auto *opCfg = opMgr->createConfiguration();

    auto *head = opMgr->heads().at(0);
    auto *cfgHead = opCfg->enableHead(head);
    //cfgHead->setScale(1.3);
    //cfgHead->setTransform(WL_OUTPUT_TRANSFORM_90);

    //opCfg->apply();
    //head->setProperty(WQt::OutputHead::Scale, "2");


//    QObject::connect(opCfg, &WQt::OutputConfiguration::succeeded, opCfg, [&qout]() {
//        qout << "OutputConfiguration::succeeded";
//    });

    //// test ////
    //auto *treelandOpMgr = reg->treeLandOutputManager();
    //treelandOpMgr->setPrimaryOutput("x11-2");

    /// Gamma


    auto *gammaMgr = reg->gammaControlManager();
    // auto name = head->property(WQt::OutputHead::Name).toString();
    wl_output* op = reg->waylandOutputs().at(0)->get();
    auto *gammaEffect = new GammaEffects(gammaMgr->getGammaControl(op));

    GammaEffectsConfig config {
        .mode = 0x8EC945,
        .gamma = 0.5,
        .brightness = 0.3,
        .minTemp = 4000,
        .maxTemp = 6500,
        .temperature = 4000,
        .latitude = 0,
        .longitude = 0,
        .sunrise = QTime( 6, 30, 0 ),
        .sunset = QTime( 18, 30, 0 ),
        .whitepoint = { 0, 0, 0 },
    };
    gammaEffect->setConfiguration(config);

    return a.exec();
}
